package com.huanletao.sync.lock02;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * 要求： 1.仓库最大容量为 20 ，2.产品数量不可能为负数。
 *
 *
 */
public class ProductLock {

    private Integer num = 0;
    private final Lock lock = new ReentrantLock();
    private final Condition produceCondition = lock.newCondition();
    private final Condition consumeCondition = lock.newCondition();
    public void produce(){
        lock.lock();
        try {
            while (num >= 20){
                System.out.println("仓库已满，生产者等待"+Thread.currentThread().getName());
                produceCondition.await();
            }
            num++;
            System.out.println("生产一个 ，当前产品数量：" + num + Thread.currentThread().getName());
            if (num>5){
                consumeCondition.signal();
            }
           // TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }

    public void consume(){
        lock.lock();
        try {
            /**
             * if 判断会有虚假唤醒问题，
             * 虚假唤醒这种情况只会出现在多线程环境中，指的是在多线程环境下，多个线程等待在同一个条件上，等到条件满足时，所有等待的线程都被唤醒，
             * 当一定的条件触发时会唤醒很多在阻塞态的线程 , 其中一部分线程从条件变量中苏醒过来时，发现等待的条件并没有满足 ,  这便是虚假唤醒
             *
             * https://blog.csdn.net/qq_42543063/article/details/125526543
             *
             *   一个被唤醒的线程就处于就绪状态了，就可以等待被cpu调度了，
             *
             *         如果用if判断的话，唤醒后线程会从wait之后的代码开始运行，但是不会重新判断if条件，直接继续运行if代码块之后的代码.
             *
             *         而使用while虽然也会从wait之后的代码开始运行，但是唤醒后会重新判断循环条件，如果不成立再执行while代码块之后的代码块，成立的话继续wait。
             *
             *         所以必须用while来检查，这样可以保证每次被唤醒都会检查一次条件。
             *
             *
             *
             */
            while (num <= 0){
                System.out.println("仓库无产品，消费者等待"+Thread.currentThread().getName());
                consumeCondition.await();
            }
            num--;
            System.out.println("消费一个 ，当前产品数量：" + num+Thread.currentThread().getName());
            if (num < 10){
                produceCondition.signal();
            }
            //TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            lock.unlock();
        }
    }
}
